package com.codebo.homiematchbackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codebo.homiematchbackend.common.ErrorCode;
import com.codebo.homiematchbackend.exception.ThrowUtils;
import com.codebo.homiematchbackend.manager.FileManager;
import com.codebo.homiematchbackend.mapper.TeamMapper;
import com.codebo.homiematchbackend.model.dto.team.JoinTeamRequest;
import com.codebo.homiematchbackend.model.dto.team.TeamAddRequest;
import com.codebo.homiematchbackend.model.dto.team.TeamQueryRequest;
import com.codebo.homiematchbackend.model.entity.Team;
import com.codebo.homiematchbackend.model.entity.TeamUser;
import com.codebo.homiematchbackend.model.entity.User;
import com.codebo.homiematchbackend.model.vo.TeamVO;
import com.codebo.homiematchbackend.service.TeamService;
import com.codebo.homiematchbackend.service.TeamUserService;
import com.codebo.homiematchbackend.service.UserService;
import com.codebo.homiematchbackend.utils.SelfUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author 25912
 * @description 针对表【team(队伍信息)】的数据库操作Service实现
 * @createDate 2025-09-14 16:49:16
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService
{
    @Resource
    private UserService userService;

    @Resource
    private TeamUserService teamUserService;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private FileManager fileManager;

    @Resource
    private SelfUtil selfUtil;

    @Override
    public long addTeam(MultipartFile multipartFile, TeamAddRequest teamAddRequest, User loginUser)
    {
        String teamname = teamAddRequest.getTeamname();
        String password = teamAddRequest.getPassword();
        String checkPassword = teamAddRequest.getCheckPassword();
        String description = teamAddRequest.getDescription();
        String avatar = teamAddRequest.getAvatar();
        List<String> tags = teamAddRequest.getTags();
        Integer maxPerson = teamAddRequest.getMaxPerson();
        Long userId = teamAddRequest.getUserId();
        Integer status = teamAddRequest.getStatus();

        //判断参数是否合法
        if (status != 0)
        {
            ThrowUtils.throwIf(password == null, ErrorCode.PARAMS_ERROR, "密码不能为空");
            ThrowUtils.throwIf(password.length() < 3 || password.length() > 20, ErrorCode.PARAMS_ERROR, "密码为3-20位");
            ThrowUtils.throwIf(!password.equals(checkPassword), ErrorCode.PARAMS_ERROR, "两次密码不一致");
        }

        ThrowUtils.throwIf(maxPerson < 1 || maxPerson > 10, ErrorCode.PARAMS_ERROR, "队伍人数不能小于1或大于10");
        ThrowUtils.throwIf(description.length() > 100, ErrorCode.PARAMS_ERROR, "描述长度不能超过100");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");
        List<Integer> list = Arrays.asList(0, 1, 2);
        ThrowUtils.throwIf(!list.contains(status), ErrorCode.PARAMS_ERROR, "队伍状态不合法");
        if (StrUtil.isBlank(teamname))
        {
            User user = userService.getById(userId);
            teamname = "用户" + user.getId() + "的队伍";
        }
        ThrowUtils.throwIf(teamname.length() > 10, ErrorCode.PARAMS_ERROR, "队伍名称不能超过10位");


        //不可重名
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamname", teamname);
        ThrowUtils.throwIf(this.count(queryWrapper) > 0, ErrorCode.PARAMS_ERROR, "队伍名称已存在");

        //存入数据库
        Team team = new Team();
        team.setTeamname(teamname);
        team.setPassword(password);
        team.setDescription(description);
        team.setAvatar(avatar);
        team.setTags(JSONUtil.toJsonStr(tags));
        team.setMaxPerson(maxPerson);
        team.setUserId(userId);
        team.setStatus(status);


        transactionTemplate.execute(transactionStatus -> {
            //存入team表
            boolean saveTeam = save(team);
            ThrowUtils.throwIf(!saveTeam, ErrorCode.SYSTEM_ERROR, "创建队伍失败");
            //存入team_user表
            TeamUser teamUser = new TeamUser();
            teamUser.setTeamId(team.getId());
            teamUser.setUserId(userId);
            boolean saveTeamUser = teamUserService.save(teamUser);
            ThrowUtils.throwIf(!saveTeamUser, ErrorCode.SYSTEM_ERROR, "创建队伍失败");
            return true;
        });

        //上传头像
        if (multipartFile != null)
        {
            String prefix = String.format("/picture/team/avatar/%s", team.getId());
            String filepath = fileManager.uploadFile(multipartFile, prefix);
            team.setAvatar(filepath);
            this.updateById(team);
        }
        return team.getId();

    }

    @Override
    public boolean joinTeam(JoinTeamRequest joinTeamRequest)
    {
        Long teamId = joinTeamRequest.getTeamId();
        Long userId = joinTeamRequest.getUserId();
        String password = joinTeamRequest.getPassword();
        ThrowUtils.throwIf(teamId == null || teamId <= 0, ErrorCode.PARAMS_ERROR, "队伍id不合法");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");

        Team team = this.getById(teamId);
        ThrowUtils.throwIf(team == null, ErrorCode.NOT_FOUND_ERROR, "队伍不存在");
        ThrowUtils.throwIf(userService.getById(userId) == null, ErrorCode.PARAMS_ERROR, "用户不存在");
        TeamVO teamVO = getTeamVO(team);
        ThrowUtils.throwIf(teamVO.getMemberVOs().size() >= team.getMaxPerson(), ErrorCode.PARAMS_ERROR, "队伍人数已满");
        ThrowUtils.throwIf(teamUserService.isJoin(teamId, userId), ErrorCode.PARAMS_ERROR, "已加入该队伍");
        ThrowUtils.throwIf(team.getStatus() == 2, ErrorCode.PARAMS_ERROR, "队伍为私有状态，不可加入");
        if (team.getPassword() != null)
        {
            ThrowUtils.throwIf(!team.getPassword().equals(password), ErrorCode.PARAMS_ERROR, "密码错误");
        }


        //操作数据库
        TeamUser teamUser = new TeamUser();
        BeanUtil.copyProperties(joinTeamRequest, teamUser);
        return teamUserService.save(teamUser);


    }

    @Override
    public List<TeamVO> listTeamByRecommend(HttpServletRequest request,
                                            TeamQueryRequest teamQueryRequest)
    {
        // 1. 当前登录用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);

        // 2. 随机 50 条队伍
        QueryWrapper<Team> queryWrapper = this.getQueryWrapper(teamQueryRequest);
        queryWrapper.getExpression().getOrderBy().clear();
        queryWrapper.last("ORDER BY RAND() LIMIT 50");
        List<Team> candidates = this.list(queryWrapper);
        if (CollUtil.isEmpty(candidates))
        {
            return Collections.emptyList();
        }

        // 3. 并行计算加权编辑距离
        Map<Team, Integer> scoreMap = new ConcurrentHashMap<>(candidates.size());
        candidates.parallelStream().forEach(t ->
        {
            int d = 0;
            d += 1 * selfUtil.editDistance(loginUser.getUserProfile(), t.getDescription());
            d += 3 * selfUtil.editDistance(loginUser.getUserTags(), t.getTags());
            scoreMap.put(t, d);
        });

        // 4. 排序并取前 10
        return candidates.stream()
                .sorted(Comparator.comparingInt(scoreMap::get))
                .limit(9)
                .map(this::getTeamVO)
                .collect(Collectors.toList());
    }


    @Override
    public TeamVO getTeamVO(Team team)
    {
        TeamVO teamVO = new TeamVO();
        BeanUtil.copyProperties(team, teamVO);
        teamVO.setTags(JSONUtil.toList(team.getTags(), String.class));
        teamVO.setUserVO(userService.getUserVO(userService.getById(team.getUserId())));
        teamVO.setMemberVOs(teamUserService.getTeamMemberVO(team.getId()));
        return teamVO;
    }

    @Override
    public QueryWrapper<Team> getQueryWrapper(TeamQueryRequest teamQueryRequest)
    {
        Long id = teamQueryRequest.getId();
        String teamname = teamQueryRequest.getTeamname();
        String description = teamQueryRequest.getDescription();
        String searchText = teamQueryRequest.getSearchText();
        List<String> tags = teamQueryRequest.getTags();
        Integer maxPerson = teamQueryRequest.getMaxPerson();
        Long userId = teamQueryRequest.getUserId();
        Integer status = teamQueryRequest.getStatus();
        Date startTime = teamQueryRequest.getStartTime();
        Date endTime = teamQueryRequest.getEndTime();
        int current = teamQueryRequest.getCurrent();
        int pageSize = teamQueryRequest.getPageSize();
        String sortField = teamQueryRequest.getSortField();
        String sortOrder = teamQueryRequest.getSortOrder();

        QueryWrapper<Team> qw = new QueryWrapper<>();
        qw.eq(ObjUtil.isNotEmpty(id), "id", id);
        qw.like(StrUtil.isNotBlank(teamname), "teamname", teamname);
        qw.like(StrUtil.isNotBlank(description), "description", description);
        if ((StrUtil.isNotBlank(searchText)))
        {
            qw.and(qw1 ->
            {
                qw1.like("teamname", searchText)
                        .or()
                        .like("description", searchText);
            });
        }
        if (CollUtil.isNotEmpty(tags))
        {
            for (String tag : tags)
            {
                qw.like("tags", tag);
//                qw.like("tags", "\"" + tag + "\"");
            }
        }
        qw.eq(ObjUtil.isNotEmpty(maxPerson), "maxPerson", maxPerson);
        qw.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        qw.eq(ObjUtil.isNotEmpty(status), "status", status);
        qw.eq(ObjUtil.isNotEmpty(status), "status", status);
// >= startEditTime
        qw.ge(ObjUtil.isNotEmpty(startTime), "create_time", startTime);
        // < endEditTime
        qw.lt(ObjUtil.isNotEmpty(endTime), "create_time", endTime);
        qw.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return qw;


    }

    @Override
    public List<TeamVO> getTeamVOList(List<Team> teams)
    {
        return teams.stream().map(this::getTeamVO).collect(Collectors.toList());
    }


}




